#!/usr/bin/env python3
import argparse
import platform
import sys,os
import subprocess
import urllib.request
import zipfile
import shutil

def printErr(content):
    sys.stderr.write('%s\n'%content)

def getCurrentScriptPath():
    dirname,filename = os.path.split(os.path.abspath(sys.argv[0]))
    return dirname

def checkCMDExists(cmd):
    return shutil.which(cmd) is not None

def forceCMDExists(cmd):
    if cmd is None:
        return False
    if not checkCMDExists(cmd):
        printErr("%s not exists" %cmd)
        return False
    return True

def printArgs(argList):
    if argList is None:
        return
    print('+',end=" ")
    for it in argList:
        print(it,end= " ")
    print("")

def runProcessAndCheckError(cmdAndParams,shell=False):
    printArgs(cmdAndParams)
    sp = subprocess.run(cmdAndParams,shell=shell)
    if sp.returncode != 0:
        printErr("Error in run command : %s"%cmdAndParams[0])
        exit(-1)

def writeFileByStrContent(filePath,content):
    f = open(filePath,mode='w')
    f.write(content)
    f.close()

def remakeTmpDirectory(tmpDir):
    if os.path.exists(tmpDir):
        if not os.path.isDir(tmpDir):
            printErr("%s exists and not a directory "%tmpDir)
            exit(-1)
        else:
            shutil.rmtree(tmpDir)
    os.makedirs(tmpDir)

def appendGccCmakeArgs(gccRoot,arch,argList):
    gccRootBin = os.path.join(gccRoot,'bin')
    arglist.append('-DCMAKE_AR=%s/%s-linux-gnu-ar'%(gccRootBin,arch))
    arglist.append('-DCMAKE_NM=%s/%s-linux-gnu-nm'%(gccRootBin,arch))
    arglist.append('-DCMAKE_OBJCOPY=%s/%s-linux-gnu-objcopy'%(gccRootBin,arch))
    arglist.append('-DCMAKE_OBJDUMP=%s/%s-linux-gnu-objdump'%(gccRootBin,arch))
    arglist.append('-DCMAKE_STRIP=%s/%s-linux-gnu-strip'%(gccRootBin,arch))
    arglist.append('-DCMAKE_LINKER=%s/%s-linux-gnu-ld'%(gccRootBin,arch))
    arglist.append('-DCMAKE_RANLIB=%s/%s-linux-gnu-ranlib'%(gccRootBin,arch))
    arglist.append('-DCMAKE_C_COMPILER=%s/%s-linux-gnu-gcc'%(gccRootBin,arch))
    arglist.append('-DCMAKE_C_COMPILER_AR=%s/%s-linux-gnu-gcc-ar'%(gccRootBin,arch))
    arglist.append('-DCMAKE_C_COMPILER_RANLIB=%s/%s-linux-gnu-gcc-ranlib'%(gccRootBin,arch))
    arglist.append('-DCMAKE_CXX_COMPILER=%s/%s-linux-gnu-g++'%(gccRootBin,arch))
    arglist.append('-DCMAKE_CXX_COMPILER_AR=%s/%s-linux-gnu-gcc-ar'%(gccRootBin,arch))
    arglist.append('-DCMAKE_CXX_COMPILER_RANLIB=%s/%s-linux-gnu-gcc-ranlib'%(gccRootBin,arch))

def appendLLVMCmakeArgs(gccRoot,arch,argList):
    gccRootBin = os.path.join(gccRoot,'bin')
    arglist.append('-DCMAKE_AR=llvm-ar')
    arglist.append('-DCMAKE_NM=llvm-nm')
    arglist.append('-DCMAKE_OBJCOPY=llvm-objcopy')
    arglist.append('-DCMAKE_OBJDUMP=llvm-objdum')
    arglist.append('-DCMAKE_STRIP=llvm-strip')
    arglist.append('-DCMAKE_LINKER=llvm-link')
    arglist.append('-DCMAKE_RANLIB=llvm-ranlib')
    arglist.append('-DCMAKE_C_COMPILER=clang')
    arglist.append('-DCMAKE_C_COMPILER_AR=llvm-ar')
    arglist.append('-DCMAKE_C_COMPILER_RANLIB=llvm-ranlib')
    arglist.append('-DCMAKE_CXX_COMPILER=clang++')
    arglist.append('-DCMAKE_CXX_COMPILER_AR=llvm-ar')
    arglist.append('-DCMAKE_CXX_COMPILER_RANLIB=llvm-ranlib')

def initGitString():
    global G_SCM_REVISION
    global G_SCM_TAG
    gitProjectDir = getCurrentScriptPath()
    # get revision string
    sp = subprocess.Popen(
            ['git','rev-parse','--short','HEAD'],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            cwd=gitProjectDir,
            encoding='utf-8')
    sp.wait()
    ret = ""
    if sp.returncode==0:
        ret = sp.stdout.read()
    else:
        printErr('Error when getting git version')
        exit(-1)
    G_SCM_REVISION = ret[0:-1]  #remove last char \n
    if len(G_SCM_REVISION) == 0:
        printErr("Error when getting git version , empty string")
        exit(-1)

    # get tag string ,unecessary
    sp = subprocess.Popen(
            ['git','tag','--points-at','HEAD'],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            cwd=gitProjectDir,
            encoding='utf-8')
    sp.wait()
    ret = ""
    if sp.returncode==0:
        ret = sp.stdout.read()
    else:
        printErr('No SCM tag')
        exit(-1)
    G_SCM_TAG = ret[0:-1]  #remove last char \n
    if len(G_SCM_TAG) == 0:
        printErr("No SCM tag")
        return

def downloadThirdParty():
    # glew
    curPath = getCurrentScriptPath()
    glewZipFile = os.path.join(curPath,'thirdparty','glew-2.1.0-win32.zip')
    glewDir = os.path.join(curPath,'thirdparty')    # extract to thirdparty
    print(platform.system())
    if platform.system() == 'Windows':
        urllib.request.urlretrieve("https://zenlayer.dl.sourceforge.net/project/glew/glew/2.1.0/glew-2.1.0-win32.zip",glewZipFile )
        with zipfile.ZipFile(glewZipFile, 'r') as zip_ref:
            zip_ref.extractall(glewDir)

def main(args):
    forceCMDExists("cmake")
    downloadThirdParty()

    emscriptenBuildDir="${curPath}/emBuild"
    localBuildDir="${curPath}/localBuild"
    buildLocalPlatform=False
    buildEmscripten=False
    buildType=args.target
    clean=args.clean
    if args.platform == 'local':
        buildLocalPlatform=True
    elif args.platform == 'empscripten':
        buildLocalPlatform=True
    else:
        buildLocalPlatform=True
        buildLocalPlatform=True
    
    if clean :
        shutil.removedirs(emscriptenBuildDir)
        shutil.removedirs(localBuildDir)
    
    if buildLocalPlatform:
        checkCMDExists("cmake")
        checkCMDExists("make")

    if buildEmscripten:
        checkCMDExists("emcmake")
        checkCMDExists("emmak")
        checkCMDExists("emmcc")

def CMakeBuild(projectDir,packageName,argDict,cmakePrefixPath = [] , customCmakeOptions=[]):
    print("building %s ......"%packageName)
    scriptPath = os.path.join(getCurrentScriptPath(),projectDir)
    installPath = os.path.abspath(os.path.join(argDict.outputDirectory,argDict.arch,packageName,argDict.buildType))
    buildType = argDict.buildType
    buildArch = argDict.arch
    buildDirectory = os.path.join(scriptPath,'testbuild',buildType)
    remakeTmpDirectory(buildDirectory)
    cmakePrefixOption = ''
    if cmakePrefixPath is not None and len(cmakePrefixPath) > 0:
        cmakePrefixOption = '-DCMAKE_PREFIX_PATH='
        cmakePrefixPathValueStr = ''
        for p in cmakePrefixPath:
            cmakePrefixPathValueStr += os.path.abspath(os.path.join(argDict.outputDirector,argDict.arch,p,argDict.buildType)) + ';'
        cmakePrefixOption+=cmakePrefixPathValueStr
    cmakeCustomOptions = ''
    if customCmakeOptions is not None and len(customCmakeOptions) > 0:
        for p in customCmakeOptions:
            cmakeCustomOptions += p + ' '

    if argDict.system == 'Windows':
        strContent = """\
call vcvarsall.bat x86_x64
cmake -B {0} -S {1} -G "Visual Studio 16 2019" \
        -DCMAKE_BUILD_TYPE={2} \
        -DCMAKE_INSTALL_PREFIX={3} {4} {5} \
        || exit /b %errorlevel%
cmake --build {0} || exit /b %errorlevel%
cmake --install {0} || exit /b %errorlevel%
        """
        strContent = strContent.format(
                buildDirectory,
                scriptPath,
                buildType,
                installPath,
                cmakePrefixOption,
                cmakeCustomOptions
                )
        tempBatchFileName = os.path.join(scriptPath,'build.bat')
        writeFileByStrContent(tempBatchFileName,strContent)
        runProcessAndCheckError(tempBatchFileName,shell=True)
    else:
        argList = [
                'cmake',
                '-B',buildDirectory,
                '-S',scriptPath,
                '-DCMAKE_BUILD_TYPE=%s'%buildType,
                '-DCMAKE_INSTALL_PREFIX=%s'%installPath,
                ]
        if cmakePrefixOption is not None and len(cmakePrefixOption) >0 :
            argList.append(cmakePrefixOption)
        if customCmakeOptions is not None and len(customCmakeOptions) >0 :
            argList.append(customCmakeOptions)
        if agDict.sysroot is not None:
            argList.append('-DCMAKE_SYSROOT=%s'%argDict.sysroot)
        if agDict.gccRoot is not None:
            appendGccCmakeArgs(argDict.gccRoot,buildArch,argList)
        runProcessAndCheckError(argList)
        runProcessAndCheckError(['cmake','--build',buildDirectory])
        runProcessAndCheckError(['cmake','--install',buildDirectory])


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Build the pocelain.')
    parser.add_argument('-p','--platform',
            type=str,
            dest='platform',
            default='all',
            choices=['empscripten','local','all'],
            help='emspcripten|local|all default: all'
            )
    parser.add_argument('-t','--target',
            dest='target',
            default="release",
            choices=['debug','release'],
            help='Build target , default: release'
            )
    parser.add_argument('-c','--clean',
            action='store_true',
            dest='clean',
            default=False,
            help='Clean build directory'
            )
    args = parser.parse_args()
    print(args)
    main(args)
